import java.util.HashMap;
import java.util.Map;

public class Parser {
	int startAdd = 0;
	int valid;
	String file;
	InstructionMemory instructionMemo;
	Map<Integer, String> fileLines;
	int linecount = 0;
	Registers RegisterFile;
	Map<String,Integer> sub_rotines;
	public Parser(String file, Registers regFile) { // file is the string of // instructions
		sub_rotines = new HashMap<String,Integer>();									
		fileLines = new HashMap<Integer, String>();
		this.file = file;
		this.valid = 0;
		this.RegisterFile = regFile;
	}

	public int compile() {
		// done for the compile button, if it returns zero then no errors,
		// if it returns integer x then print "error at line x"
		String[] lines = file.split("\n");
		for (int i = 0; i < lines.length; i++) {
			if (!verify(lines[i], i)) {
				valid = i + 1;
				break;
			}
		}
		return valid;
	}

	public boolean Run() { // when it compiles successfully (returning 0) RUN
							// button appears
							// this method passes the instructions from the text
							// field to the instruction memory
							//
		String[] lines = file.split("\n");
		if (valid == 0) {
			int j = startAdd;
			for (int i = 0; i < lines.length; i++) {
				if ((i == 0 && lines[0].toLowerCase().contains("org")) || lines[i] == "" || lines[i] == null)
					continue;
				else {
					fileLines.put(j, findComments(lines[i]));
					j += 4;
					linecount++;
				}
			}
			instructionMemo = new InstructionMemory(startAdd, fileLines, RegisterFile, sub_rotines);
			return true;
		} else {
			return false;
		}
	}

	public boolean verify(String line, int i) {

		line = findComments(line);

		for (int j = 0; j < line.length(); j++)
			// finds labels
			if (islabel(line) && line.charAt(j) == ':') {
				sub_rotines.put(line.substring(0, j),i*4);
				if (j + 1 <= line.length()) {
					System.out.println("sub 2 : "+sub_rotines.get("sub"));
					line = line.substring(j + 1, line.length());
					break;
			}
			}
		while(true){
			if (line.isEmpty())
				return true;
			if (line.startsWith(" ")) 
				line = line.substring(1, line.length());
			else
				break;
		}
		if (line.toLowerCase().contains("org")) {
			if (i == 0) {
				startAdd = Integer.parseInt(line.split(" ")[1]);
				return true;
			} else
				return false;
		}
		String[] l = line.split("[\\s,:]+");
		if (l[0].equals("slti") || l[0].equals("ori") || l[0].equals("andi") || l[0].equals("srl") || l[0].equals("addi")
				|| l[0].equals("sltui") || l[0].equals("sll")) {
			if (l.length == 4) {
				return (validRegister(l[1]) && validRegister(l[2]) && validInteger(l[3]));
			}
		}

		if (l[0].equals("nor") || l[0].equals("slt") || l[0].equals("or") || l[0].equals("and") || l[0].equals("sub")
				|| l[0].equals("sltu") || l[0].equals("add")) {
			if (l.length == 4) {
				return (validRegister(l[1]) && validRegister(l[2]) && validRegister(l[3]));
			}
		}

		if (l[0].equals("lw") || l[0].equals("sw")) {
			if (l.length == 3) {
				return (checkMemo(l[2]) && validRegister(l[1]));
			}
		}
		if (l[0].equals("bne") || l[0].equals("jr") || l[0].equals("beq")) {

			if (l.length == 4) {
				return (validRegister(l[1]) && validRegister(l[2]) && !validRegister(l[3]) && !validInteger(l[3]));
			}
			if (l.length == 2) {
				return validRegister(l[1]);
			}
		}
		if (l[0].equals("jal") || l[0].equals("j")) {
			if (l.length == 2)
				return (!validRegister(l[1]) && !validInteger(l[1]));
		}
		if (l[0].toLowerCase().equals("hlt"))
			if (l.length == 1)
				return true;
		return false;
	}

	public boolean checkMemo(String s) { // checks if string s is in the form
											// n($t1)
		String[] l = s.split("[()]");
		if (l.length == 2)
			return validInteger(l[0]) && validRegister(l[1]);
		if (l.length == 1)
			return validRegister(l[0]);

		return false;
	}

	public boolean validRegister(String x) { // checks if String x is a register
		Registers t = new Registers();
		if (t.isReg(x))
			return true;
		return false;
	}

	public boolean validInteger(String x) { // checks if string x is an integer
		try {
			Integer.parseInt(x);
			return true;

		} catch (Exception e) {

			return false;
		}
	}

	public static boolean islabel(String line) {
		// public method to check if the String line is a label
		// or if it starts with a label
		String[] l = line.split(":");
		if (l[0].split(" ").length == 1)
			return true;
		return false;
	}

	public String findComments(String line) {
		for (int j = 0; j < line.length(); j++)
			// finds comments
			if (line.charAt(j) == '#')
				return line.substring(0, j);
		return line;
	}

	public static void main(String[] ha3) {
		String file = "label:addi $s1, $s0, 6\naddi $s0 , $s1 ,2";
//		Parser p = new Parser(file);
//		p.compile();
//		p.Run();
		// System.out.println();
		// InstructionMemory m = new InstructionMemory(0,p.fileLines);
	}

	public void setInstructions(String s) {
		this.file = s;
	}
}
